
/**
 * Project Name:cats-web
 * File Name:UserFilterInvocationSecurityMetadataSource.java
 * Package Name:com.catsic.core.web.authority
 * Date:2014年3月11日下午4:15:54
 * Copyright (c) 2014, oa.catsic.com All Rights Reserved.
 */
 
package com.catsic.security.authority;

import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;

import com.catsic.core.constants.Constants;
import com.catsic.core.entity.Resource;
import com.catsic.core.entity.Role;
import com.catsic.core.role.service.RoleService;
import com.catsic.pub.drawer.service.DrawerService;
import com.catsic.pub.entity.Drawer;

/**
 * ClassName: UserFilterInvocationSecurityMetadataSource
 * Description: 用户权限资源加载类，从数据库提取权限和资源
 * date: 2014年3月11日 下午4:15:54
 * author: yangyd
 */
@Component("userSecurityMetadataSource")
public class UserFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
	
	@Autowired
	private FilterChainProxy securityFilterChain;
	
	@Autowired
	private RoleService roleService;
	
	@Autowired
	private DrawerService drawerService;

	private static Map<RequestMatcher, Collection<ConfigAttribute>> requestMap = null;
	
	public UserFilterInvocationSecurityMetadataSource(){
	}
	
	public UserFilterInvocationSecurityMetadataSource(
            LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap) {
		loadResourceDefine();
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        Set<ConfigAttribute> allAttributes = new HashSet<ConfigAttribute>();
        return allAttributes;
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) {
    	Drawer drawer = drawerService.findByCode(Constants.是否启用权限缓存);
    	if(requestMap == null || requestMap.size() == 0 || !Constants.权限缓存开关设置.equals(drawer.getValue())){
    		loadResourceDefine();
		}
        final HttpServletRequest request = ((FilterInvocation) object).getRequest();

        for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap.entrySet()) {
        	if (entry.getKey().matches(request)) {
                return entry.getValue();
            }
        }
        
        //throw new AccessDeniedException("无权限_拒绝访问");
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }
    
   /**
    * loadResourceDefine:加载所有资源与角色的关系    
    * @author yangyd
    */
	private void loadResourceDefine(){
		requestMap = new ConcurrentHashMap<RequestMatcher, Collection<ConfigAttribute>>();  		
		List<Role> list = roleService.findAll();
        for(Role role : list){
        	List<Resource> resources = role.getResources();
            for(Resource resource : resources){
            	if(StringUtils.isNotEmpty(resource.getPattern())){
            		getMap(role.getName(),resource.getPattern());
            	}
            	
            	if(StringUtils.isNotEmpty(resource.getViews())){
            		getMap(role.getName(),resource.getViews());
            	}
            }
        }
        /**
         * 匿名认证，所有anonymous文件夹下的可以不用登陆系统，便可访问
         * 使用匿名认证，spring-security.xml文件中的39，53行代码注释打开 
         **/
        /*getMap("ROLE_ANONYMOUS", "/anonymous/**");*/
    } 
	
	private synchronized void getMap(String roleName, String resource){
		Collection<ConfigAttribute> configAttributes =  new LinkedHashSet<ConfigAttribute>();  
    	ConfigAttribute configAttribute = new SecurityConfig(roleName);
		
		RequestMatcher requestMatcher = new AntPathRequestMatcher(resource);
        /**
         * 如果requestMatcher已经含有pattern，
         * 则requestMap的key值requestMatcher保持不变
         * 仅将pattern对应的角色添加至requestMap的value值Collection<ConfigAttribute>
         * 否则requestMap新添加pattern与configAttributes
         **/
        if (requestMap.containsKey(requestMatcher)){
        	Collection<ConfigAttribute> value = requestMap.get(requestMatcher);
        	value.add(configAttribute);
        	//requestMap.put(requestMatcher, value);  
        }else{
        	configAttributes.add(configAttribute); 
        	requestMap.put(requestMatcher, configAttributes);  
        }
	}
}
